import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import pearsonr
def calculate_polarization(beliefs_np):
    """
    计算每轮的极化度 (Pz)，返回形状为 (T,) 的数组

    参数:
        beliefs_np: NumPy数组，形状为 (N, T)，N是代理数，T是轮次数

    返回值:
        polarization_per_round: 每轮的极化度，形状为 (T,)
    """
    mean_belief_per_round = np.mean(beliefs_np, axis=0)  # 按轮次计算均值，形状(T,)
    polarization_per_round = np.mean((beliefs_np - mean_belief_per_round) ** 2, axis=0)  # 按轮次计算方差，形状(T,)
    return polarization_per_round


def calculate_global_disagreement(adjacency_matrix, beliefs_np):
    """
    计算每轮的全局分歧度 (DG)，返回形状为 (T,) 的数组

    参数:
        adjacency_matrix: 邻接矩阵，形状为 (N, N)
        beliefs_np: NumPy数组，形状为 (N, T)，N是代理数，T是轮次数

    返回值:
        dg_per_round: 每轮的全局分歧度，形状为 (T,)
    """
    N, T = beliefs_np.shape
    dg_per_round = np.zeros(T)  # 初始化每轮的DG值

    for t in range(T):  # 遍历每一轮
        total_dg = 0.0
        for i in range(N):  # 遍历每个代理
            neighbors = np.where(adjacency_matrix[i] == 1)[0]  # 代理i的邻居
            if len(neighbors) == 0:
                continue
            # 计算代理i在第t轮与邻居的信念差异的均值
            diff = np.mean(np.abs(beliefs_np[i, t] - beliefs_np[neighbors, t]))
            total_dg += diff
        dg_per_round[t] = total_dg  # 存储第t轮的DG值

    return dg_per_round


def calculate_nci(adjacency_matrix, beliefs_np):
    """
    计算每轮的归一化聚类指数 (NCI)，返回形状为 (T,) 的数组

    参数:
        adjacency_matrix: 邻接矩阵，形状为 (N, N)
        beliefs_np: NumPy数组，形状为 (N, T)，T >= 2

    返回值:
        nci_per_round: 每轮的NCI值，形状为 (T,)

    注意:
        - 如果 T < 2，无法计算相关系数，会抛出异常
        - 每个轮次的NCI是基于当前轮及之前所有轮次的数据计算的
    """
    N, T = beliefs_np.shape
    nci_per_round = np.zeros(T)

    for t in range(T):
        # 需要至少2轮数据计算相关系数
        if t < 1:
            nci_per_round[t] = 0.0  # 第0轮无法计算，设为0
            continue

        # 提取从第0轮到第t轮的信念值（形状 (N, t+1)）
        cumulative_beliefs = beliefs_np[:, :t + 1]

        nci_values = []
        for i in range(N):
            neighbors = np.where(adjacency_matrix[i] == 1)[0]
            if len(neighbors) == 0:
                nci_values.append(0.0)
                continue

            # 计算代理i与每个邻居的相关系数
            correlations = []
            for j in neighbors:
                r, _ = pearsonr(cumulative_beliefs[i, :], cumulative_beliefs[j, :])
                correlations.append(r)

            nci_values.append(np.mean(correlations))

        nci_per_round[t] = np.mean(nci_values)  # 存储第t轮的NCI

    return nci_per_round
def create_ring_adjacency_matrix(n_nodes):
    """
    生成环状连接的邻接矩阵

    参数:
        n_nodes: 节点数量（例如4表示1-2-3-4-1的环）

    返回值:
        adjacency_matrix: NumPy数组，形状为(n_nodes, n_nodes)，邻接矩阵
    """
    adjacency_matrix = np.zeros((n_nodes, n_nodes), dtype=int)  # 初始化全零矩阵

    for i in range(n_nodes):
        # 前一个节点（如果i=0，前一个节点是n_nodes-1）
        prev = (i - 1) % n_nodes
        # 后一个节点（如果i=n_nodes-1，后一个节点是0）
        next_ = (i + 1) % n_nodes
        adjacency_matrix[i][prev] = 1  # 连接前一个节点
        adjacency_matrix[i][next_] = 1  # 连接后一个节点

    return adjacency_matrix


# 示例：生成4个节点的环状邻接矩阵（1-2-3-4-1）
n_nodes = 8
adjacency_matrix = create_ring_adjacency_matrix(n_nodes)
print("邻接矩阵（4节点环状结构）:")
print(adjacency_matrix)



beliefs_agents = np.array([[0.5, 1.0, 1.2, 1.3, 1.6, 1.7, 2.0, 2.0, 2.0, 2.0],
                           [0.3, 0.7, 1.0, 1.3, 1.6, 1.7, 1.8, 2.0, 2.0, 1.9],
                           [0.5, 0.7, 0.8, 1.0, 1.1, 1.2, 1.3, 2.0, 2.0, 2.0],
                           [0.3, 0.6, 0.7, 1.0, 1.2, 1.3, 1.5, 1.8, 2.0, 2.0],
                           [0.7, 0.5, 0.8, 0.9, 1.1, 1.2, 1.3, 1.2, 1.8, 2.0],
                           [1.5, 1.2, 0.8, 0.6, 0.5, 0.3, 0.2, -0.1, -0.2, -0.4],
                           [-0.5, -0.3, -0.1, 0.0, 0.2, 0.5, 0.7, 0.8, 0.6, 0.4],
                           [1.3, 0.9, 0.8, 0.7, 0.8, 0.9, 1.0, 1.1, 1.0, 0.9]])

# 打印结果（设置打印格式保留两位小数）
np.set_printoptions(precision=2)
print("生成的信念值数组形状:", beliefs_agents.shape)
print("数组内容:\n", beliefs_agents)

p=calculate_polarization(beliefs_agents)
print(p)

g=calculate_global_disagreement(adjacency_matrix,beliefs_agents)
print(g)

n=calculate_nci(adjacency_matrix,beliefs_agents)
print((n))


# 设置中文字体（确保你的系统支持中文字体，否则会报错）
plt.rcParams['font.sans-serif'] = ['SimHei']  # 例如使用黑体
plt.rcParams['axes.unicode_minus'] = False    # 解决负号显示问题
# 创建画布和子图
plt.figure(figsize=(12, 8))

# 绘制极化度 (Pz)
plt.subplot(3, 1, 1)
plt.plot(range(1, 11), p, marker='o', linestyle='-', color='blue', label='极化度 (Pz)')
plt.xlabel('轮次')
plt.ylabel('极化度')
plt.title('极化度 (Pz) 随轮次变化')
plt.grid(True)
plt.legend()

# 绘制全局分歧度 (DG)
plt.subplot(3, 1, 2)
plt.plot(range(1, 11), g, marker='s', linestyle='--', color='red', label='全局分歧度 (DG)')
plt.xlabel('轮次')
plt.ylabel('分歧度')
plt.title('全局分歧度 (DG) 随轮次变化')
plt.grid(True)
plt.legend()

# 绘制归一化聚类指数 (NCI)
plt.subplot(3, 1, 3)
plt.plot(range(1, 11), n, marker='^', linestyle='-.', color='green', label='归一化聚类指数 (NCI)')
plt.xlabel('轮次')
plt.ylabel('NCI')
plt.title('归一化聚类指数 (NCI) 随轮次变化')
plt.grid(True)
plt.legend()

# 调整布局并显示
plt.tight_layout()
plt.savefig('指标变化趋势.png', dpi=300)  # 保存为PNG图片
plt.show()

